package com.join.mybatis.mapping;


import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.metadata.TableInfo;
import com.join.mybatis.enums.MySqlMethod;
import com.join.mybatis.handle.JoinClumnHandle;
import com.join.mybatis.method.JoinColumnConfig;
import com.join.mybatis.method.JoinField;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.mapping.ResultMap;
import org.apache.ibatis.mapping.ResultMapping;
import org.apache.ibatis.session.Configuration;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;

/**
 * @author chengang
 */
public class MyMapperRegister {

    public final static String placeholder="_info";

    public String registerResultMap(Configuration configuration,Class mapperClass,Class modelClass,TableInfo tableInfo){
        String id=mapperClass.getName()+".myResultMap";
        if(!configuration.hasResultMap(id)){
            configuration.addResultMap(new ResultMap.Builder(configuration,id,
                    modelClass,getMapping(configuration,modelClass,mapperClass,tableInfo)).build());
        }
        return id;
    }

    private List<ResultMapping> getMapping(Configuration configuration,Class modelClass,Class mapperClass,TableInfo tableInfo){
        List<ResultMapping> resultMappingList=new ArrayList<>();
        JoinColumnConfig.fieldsMap.get(modelClass).forEach((k, v)->{
            if(v.getJoinClumnConfig().getUseJavaType()){
                    Arrays.stream(v.getResultClumns()).forEach(it->{
                        //
                        ResultMapping resultMapping = filedType(configuration, v, it);
                        if(Objects.nonNull(resultMapping))resultMappingList.add(resultMapping);
                    });
            }else{
                ResultMapping resultMapping=new ResultMapping.Builder(configuration,v.getFieldName(), v.getFieldName()+placeholder, new JoinClumnHandle(modelClass, v.getFieldClazz(),v.getFieldName())).build();
                resultMappingList.add(resultMapping);
            }
        });
        JoinColumnConfig.oneToManyMap.get(modelClass).forEach((k, v)->{
            ResultMapping resultMapping = fieldList(configuration, mapperClass,tableInfo,v);
            if(Objects.nonNull(resultMapping))resultMappingList.add(resultMapping);
        });
        return resultMappingList;
    }
    private ResultMapping fieldList(Configuration configuration, Class<?> mapperClass, TableInfo tableInfo, JoinField field){
       return new ResultMapping.Builder(configuration, field.getFieldName(), tableInfo.getKeyColumn(), List.class)
                .jdbcType(null)
                .nestedQueryId(mapperClass.getName()+"."+String.format(MySqlMethod.SELECT_ONETOMANY_LIST.getMethod(),field.getFieldName()))
                .nestedResultMapId(null)
                .resultSet(null)
                .typeHandler(null)
                .flags(new ArrayList<>())
                .composites(new ArrayList<>())
                .notNullColumns(null)
                .columnPrefix(null)
                .foreignColumn(null)
                .lazy(field.getLazy())
                .build();
    }
    private ResultMapping filedType(Configuration configuration, JoinField field,String column){
        Field declaredField=null;
        try {
            declaredField = field.getFieldClazz().getDeclaredField(StrUtil.toCamelCase(column));
        } catch (NoSuchFieldException e) {
            //Ignore null cases
            try {
                declaredField = field.getFieldClazz().getSuperclass().getDeclaredField(StrUtil.toCamelCase(column));
            } catch (NoSuchFieldException noSuchFieldException) {
                return null;
            }

        }
        try {
            return new ResultMapping.Builder(configuration, field.getFieldName()+"."+StrUtil.toCamelCase(column), StrUtil.toCamelCase(field.getJoinTableInfo().getTableName()+"_"+column),declaredField .getType())
                    .nestedQueryId(null)
                    .nestedResultMapId(null)
                    .resultSet(null)
                    .typeHandler(null)
                    .flags(new ArrayList<>())
                    .composites(new ArrayList<>())
                    .notNullColumns(null)
                    .columnPrefix(null)
                    .foreignColumn(null)
                    .lazy(field.getLazy())
                    .build();
        } catch (Exception e) {
            return null;
        }
    }
}
